// 渲染模块
import fragShader from './main.glsl?raw'
import { u } from './util'
import { map, mapHeight, updateTiles } from './game'
import url from './tex.avif?url'
import { error } from '@cydon/ui/Message'
import { mapWidth } from './defs'
import { Coord, World } from './tino'

export type Pixels = HTMLImageElement | Uint8Array | Uint8ClampedArray

export class Factories extends World {
	_offset: Coord = [0, 0]
	_selectedSlot = 0

	texture: Pixels = new Image()
	pr!: WebGLProgram
	uFlags!: WebGLUniformLocation
	uSelectedSlot!: WebGLUniformLocation
	uOffset!: WebGLUniformLocation

	/** 获取建筑纹理 */
	get buildingTexture() {
		return this.texture
	}
	/** 设置建筑纹理 */
	set buildingTexture(v: Pixels) {
		this.texture = v
		if (v instanceof Image)
			v.decode().then(() => this.setTexture(0, 'tex', this.texture))
		else
			this.setTexture(0, 'tex', this.texture)
	}

	/** 获取偏移 */
	get offset() {
		return this._offset
	}
	/** 设置偏移 */
	set offset(coord) {
		let [x, y] = coord
		// 保证x和y是偶数
		x &= ~1;
		y &= ~1;
		this._offset = coord
		this.gl.uniform2f(this.uOffset, x, y)
		x /= this.slotSize
		y /= this.slotSize
		updateTiles(u(x + y * mapWidth), u(x + mapWidth), u(y + mapHeight))
		this.setTexture(1, 'map', map)
	}

	/** 获取当前选中的块号 */
	get selectedSlot() {
		return this._selectedSlot
	}
	/** 选择建筑 */
	select(x: number, y: number) {
		x = (x + this.offset[0]) / this.canvas.width
		y = (y + this.offset[1]) / this.canvas.width
		const scale = this.scale
		let slot = x / scale | y / scale << 6
		if (slot == this.selectedSlot) {
			slot = -1
		}
		this.gl.uniform1i(this.uSelectedSlot, this._selectedSlot = slot)
	}

	constructor() {
		super(<HTMLCanvasElement>document.getElementById('app'))
		if (this.texture instanceof Image)
			this.texture.src = url
		try {
			const pr = this.pr = this.shader(fragShader)
			const uniform = (name: string) => this.gl.getUniformLocation(pr, name)!
			this.uFlags = uniform('flags')
			this.uSelectedSlot = uniform('selectedSlot')
			this.select(0, 0)
			this.uOffset = uniform('offset')
			this.buildingTexture = this.texture
		} catch (e) {
			error((<Error>e).message)
		}
	}

	/** 设置显示选项 */
	setOptions(opts: number) {
		console.assert(opts >= 0 && opts < 16)
		this.gl.uniform1i(this.uFlags, opts)
	}

	/** 更新纹理 */
	setTexture(index: 0 | 1 | 2 | 3, name: string, pixels?: Pixels) {
		const gl = this.gl

		if (!pixels) {
			gl.deleteTexture(gl.getParameter(gl.TEXTURE_BINDING_2D))
			return
		}
		const texture = gl.createTexture()
		gl.activeTexture(gl[`TEXTURE${index}`])
		gl.bindTexture(gl.TEXTURE_2D, texture)

		// 设置纹理 缩放渐变相关
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)

		// 将像素传入绘制到纹理上
		if (pixels instanceof Uint8Array)
			gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, mapWidth, mapHeight, 0,
				gl.RGBA, gl.UNSIGNED_BYTE, pixels, 0)
		else if (pixels instanceof Uint8ClampedArray)
			gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 256, 8, 0,
				gl.RGB, gl.UNSIGNED_BYTE, pixels, 0)
		else
			gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, pixels)

		// 将纹理序号使用uniform绑定到程序里
		gl.uniform1i(gl.getUniformLocation(this.pr, name), index)
	}
}


export default new Factories()
